﻿using System;
using System.Linq;
using System.Xml.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using SoftwareLogistics.SharepointClient.Library;
using SoftwareLogistics.SharepointClient.Library.Models;

namespace SoftwareLogistics.SharepointClient
{
    public enum FieldTypes
    {
        Unknown,
        Guid,
        Boolean,
        Integer,
        Text,
        Note,
        Choice,
        Number,
        Lookup,
        DateTime,
        User,
        ContentTypeId,
        Attachments,
        Computed
    }

    public class SPField
    {

        public string Name { get; set; }
        public string InternalName { get; set; }
        public string ID { get; set; }
        public int? NumberDecimal { get; set; }
        public double? Min { get; set; }
        public double? Max { get; set; }
        public FieldTypes FieldType { get; set; }
        public string ColName { get; set; }
        public string Format { get; set; }
        public bool Required { get; set; }
        public bool ReadOnly { get; set; }
        public bool Hidden { get; set; }
        public bool IsList { get; set; }
        public string DisplayName { get; set; }
        public string Default { get; set; }
        public string Value { get; set; }
        public List<string> Choices { get; set; }
        public IEditField Editor { get; set; }

        public static SPField Create(XElement element)
        {
            var field = new SPField()
            {
                ID = (string)element.Attribute("ID"),
                Name = (string)element.Attribute("Name"),
                InternalName = (string)element.Attribute("InternalName"),
                Format = (string)element.Attribute("Format"),
                DisplayName = (string)element.Attribute("DisplayName"),
                Default = (string)element.Attribute("Default")
            };

            var defaultNode = element.Descendants(XName.Get("Default",Common.SP_NS)).FirstOrDefault();
            if(defaultNode != null)
                field.Default = defaultNode.Value;

            var fieldType = (string)element.Attribute("Type");

            var numberDecimals = (string)element.Attribute("Decimals");
            if(numberDecimals != null)
                field.NumberDecimal = Convert.ToInt32(numberDecimals);

            var minAttr = (string)element.Attribute("Min");
            if(minAttr != null)
                field.Min = Convert.ToDouble(minAttr);

            var maxAttr = (string)element.Attribute("Max");
            if(maxAttr != null)
                field.Max = Convert.ToDouble(maxAttr);

            if (string.IsNullOrEmpty(fieldType))
                field.FieldType = FieldTypes.Unknown;
            else
            {
                switch (fieldType.ToLower())
                {
                    case "text": field.FieldType = FieldTypes.Text; break;
                    case "note": field.FieldType = FieldTypes.Note; break;
                    case "choice": field.FieldType = FieldTypes.Choice; break;
                    case "number": field.FieldType = FieldTypes.Number; break;
                    case "lookup": field.FieldType = FieldTypes.Lookup; break;
                    case "datetime": field.FieldType = FieldTypes.DateTime; break;
                    case "user": field.FieldType = FieldTypes.User; break;
                    case "boolean": field.FieldType = FieldTypes.Boolean; break;
                    case "guid": field.FieldType = FieldTypes.Guid; break;
                    case "integer": field.FieldType = FieldTypes.Integer; break;
                    case "computed": field.FieldType = FieldTypes.Computed; break;
                    case "contenttypeid": field.FieldType = FieldTypes.ContentTypeId; break;
                    case "attachments": field.FieldType = FieldTypes.Attachments; break;
                    default: field.FieldType = FieldTypes.Unknown;
                        Debug.WriteLine("UNKNOWN TYPE-> " + fieldType.ToLower());                       
                        break;
                }
            }

            var choices = element.Descendants(XName.Get("CHOICE", "http://schemas.microsoft.com/sharepoint/soap/"));
            field.IsList = choices.Count() > 0;
            if (field.IsList)
            {
                field.Choices = new List<string>();
                foreach (var choice in choices)
                {
                    if(!string.IsNullOrEmpty(choice.Value))
                        field.Choices.Add(choice.Value);
                }
            }

            field.Required =  element.Attribute("Required") == null ? false : ((string)element.Attribute("Required")).ToLower() == "true";
            field.Hidden = element.Attribute("Hidden") == null ? false : ((string)element.Attribute("Hidden")).ToLower() == "true";
            field.ReadOnly = element.Attribute("ReadOnly") == null ? false : ((string)element.Attribute("ReadOnly")).ToLower() == "true";

            return field;
        }

        public ValidationIssue Validate()
        {
            if (Editor != null)
            {
                Editor.RefreshValue();

                if (string.IsNullOrEmpty(Value) && Required)
                    return new ValidationIssue(string.Format("{0} is a required field.", DisplayName));

                if (string.IsNullOrEmpty(Value))
                    return null;

                switch(FieldType)
                {
                    case FieldTypes.Boolean:
                        Boolean b;
                        if (Value == "1") 
                            Value = "TRUE";

                        if (Value == "0")
                            Value = "FALSE";

                        if (!Boolean.TryParse(Value, out b))
                            return new ValidationIssue(String.Format("Please enter a valid value for : {0}", DisplayName));

                        break;
                    case FieldTypes.DateTime:
                        DateTime dat;
                        if(!DateTime.TryParse(Value, out dat))
                            return new ValidationIssue(String.Format("Please enter a valid date for: {0}", DisplayName));

                        break;
                    case FieldTypes.Integer:
                        int i;
                        if(!Int32.TryParse(Value, out i))
                            return new ValidationIssue(String.Format("Please enter an integer value for: {0}", DisplayName));

                        break;
                    case FieldTypes.Number:
                        double d;
                        if (!Double.TryParse(Value, out d))
                            return new ValidationIssue(String.Format("Please enter a numeric value for: {0}", DisplayName));
                        else
                        {
                            if(d > Max)
                                return new ValidationIssue(String.Format("The maximum value for {0} is: {1}", DisplayName, Max));

                            if(d < Min)
                                return new ValidationIssue(String.Format("The minimum value for {0} is: {1}", DisplayName, Min));
                        }
                        break;
                }
                
                return null;
            }
            else
                return null;
        }

        public string GetFormattedNumber()
        {
            if (string.IsNullOrEmpty(Value))
                return string.Empty;
            else
            {
                var formatString = "{0:0.";
                var numbDecimals = NumberDecimal ?? 0;
                for (var idx = 0; idx < numbDecimals; ++idx)
                    formatString += "0";

                formatString += "}";

                return string.Format(formatString, Convert.ToDouble(Value));
            }
        }

        public string GetFormattedLookupValue()
        {
            if (string.IsNullOrEmpty(Value))
                return "[no title]";
            else
            {
                string[] parts = Value.Split(';');
                return parts.Length > 1 ? parts[1].TrimStart('#') : parts[0];
            }
        }

        public SPUser GetUser()
        {
            if (!string.IsNullOrEmpty(Value))
            {
                var id = Value.Split(';')[0];
                return Common.Users.Users.Where(usr => usr.ID.ToString() == id).FirstOrDefault();
            }
            else
                return null;
        }

        public DateTime? GetDateTime()
        {
            if (!string.IsNullOrEmpty(Value))
            {
                if (Value.Contains("today"))
                    return DateTime.Today;
                else
                    return DateTime.Parse(Value);
            }

            return null;
        }

        public Boolean? GetIsChecked()
        {
            if (string.IsNullOrEmpty(Value))
                return false;
            else
                return (Value.ToLower() == "true" || Value == "1");
        }


        public override string ToString()
        {
            return string.Format("{0} - {1} {2} {3} {4} Required: {5}, Hidden {6}", ID, FieldType, DisplayName, Name, InternalName, Required, Hidden);
        }

    }
}
